#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "MSTK.h"
#include <mpi.h>

void itoa(int n, char s[]);
void reverse(char s[]);

int main(int argc, char *argv[]) {
  int i, k, ok;
  char mname[256],filename[256];
  char buf[256];
  char subfilename[256];
  Mesh_ptr mesh, recv_mesh, *submeshes;
  RepType rtype;
  /* default divide into two parts */
  int num = 3;
  int rank;

  /* command line parameter */
  MPI_Init(&argc,&argv);
  MPI_Comm_size(MPI_COMM_WORLD,&num);
  MPI_Comm_rank(MPI_COMM_WORLD,&rank);
  printf ("Number of tasks= %d My rank= %d\n", num,rank);

  

  /* initialize MPI data type */
  MESH_InitializeMPI();

  /* Load the mesh */
  strcpy(mname,"mesh/pig");
  strcpy(filename,mname);
  strcat(filename,".mstk");
    
  /* master process read in and divide the mesh */
  if(rank == 0) { 
    /* Initialize MSTK - Always do this even if it does not seem to
    matter in this version of MSTK */
    MSTK_Init();  
    mesh = MESH_New(UNKNOWN_REP);
    ok = MESH_InitFromFile(mesh,filename);
    if (!ok) {
      fprintf(stderr,"Cannot open input file %s\n\n\n",filename);
      exit(-1);
    }
    fprintf(stdout,"mstk mesh %s read in successfully\n",filename);
    
    /* Partition the mesh*/
    rtype = MESH_RepType(mesh);
    submeshes = (Mesh_ptr *)MSTK_malloc((num-1)*sizeof(Mesh_ptr));
    ok = MESH_Partition(mesh,submeshes,(num-1));
    fprintf(stdout,"%s has been partitioned into %d submeshes\n",filename,num-1);
    
    

    for (i = 0 ; i < num-1 ; i++) {
      strcpy(subfilename,mname);
      itoa(i,buf);
      strcat(subfilename,buf);
      strcat(subfilename,".mstk");
      MESH_WriteToFile(submeshes[i],subfilename,rtype);
      /* built ptype */
      MESH_BuildPType(mesh,submeshes[i]);
      /* add ghost */
      MESH_AddGhost(mesh,submeshes[i],1);
      fprintf(stdout,"PType and Ghost of submesh %d has been built\n",i);
      strcpy(subfilename,mname);
      itoa(i,buf);
      strcat(subfilename,buf);
      strcat(subfilename,"-add-ghost.mstk");
      /* write regular mstk mesh */
      MESH_WriteToFile(submeshes[i],subfilename,rtype);
      fprintf(stdout,"submesh %d has been written into %s\n",i,subfilename);
      strcpy(subfilename,mname);
      itoa(i,buf);
      strcat(subfilename,buf);
      strcat(subfilename,"-P-add-ghost.mstk");
      /* write parallel mstk mesh */
      PMESH_WriteToFile(submeshes[i],subfilename,rtype);
      fprintf(stdout,"parallel submesh %d has been written into %s\n",i,subfilename);
      printf("after pmesh write:submesh reptype %d\n",MESH_RepType(submeshes[i]));
    
      fprintf(stdout,"begin send submesh %d \n",i+1);
      MESH_Surf_SendMesh(submeshes[i],i+1,MPI_COMM_WORLD);
      fprintf(stdout,"submesh %d sent\n",i+1);
    
    }
  }

  /*  MPI_Barrier(MPI_COMM_WORLD);
  printf("after barrier\n");
  */    
  /* send submeshes */
  /*  if(rank == 0) {
    for(i = 0; i < num - 1; i++) {
      fprintf(stdout,"begin send submesh %d \n",i+1);
      printf("mesh reptype %d\n",MESH_RepType(submeshes[i]));
      MESH_Surf_SendMesh(submeshes[i],i+1,MPI_COMM_WORLD);
      fprintf(stdout,"submesh %d sent\n",i+1);
    }  
  }

  */

  if(rank != 0) {
    recv_mesh = MESH_New(F1);

    fprintf(stdout,"begin receive submesh %d \n",rank);
    MESH_RecvMesh(recv_mesh,2,rank,MPI_COMM_WORLD);
    fprintf(stdout,"submesh %d received\n",rank);
  }
 
  if(rank == 0) {
    /* Deleting of mesh is not necessary if this the end of the program */
    for (i = 0; i < num-1; i++)
      MESH_Delete(submeshes[i]);
    /* Write out a copy of the mesh */
    
    strcpy(filename,mname);
    strcat(filename,"-copy.mstk");
    MESH_WriteToFile(mesh,filename,rtype);
  }
 
  MESH_FinalizeMPI();
  MPI_Finalize();
  return 1;
}

 void itoa(int n, char s[]) {
    int i, sign;
    sign = n;
    
    i = 0;
    do {
      s[i++] = abs(n % 10) + '0';
    } while ( n /= 10 );
    if (sign < 0)
      s[i++] = '-';
    
    s[i] = '\0';
    reverse(s);
  }
  void reverse(char s[]) {
    int c, i, j;
    for ( i = 0, j = strlen(s)-1; i < j; i++, j--) {
      c = s[i];
      s[i] = s[j];
      s[j] = c;
    }
  }  
